<!--
 * Copyright 2020 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
-->

<script language="javascript">
class ExtensionPluginBase {
  constructor(impl) {
    this._impl = impl;
  }

  dispose() {
  }

  /*async */ removeRawModule(rawModuleId) {
    if (this._impl.removeRawModule) {
      return this._impl.removeRawModule(rawModule);
    }
    return Promise.resolve();
  }

  /** Notify the plugin about a new script
   * @param {string} rawModuleId
   * @param {string} symbols - URL of a file providing the debug symbols for this module
   * @param {!{url: string}} rawModule
   * @return {!Promise<!Array<string>>} - An array of absolute or relative URLs for the source files for the raw module
   */
  /*async */ addRawModule(rawModuleId, symbols, rawModule) {
    if (this._impl.addRawModule) {
      return this._impl.addRawModule(rawModuleId, symbols, rawModule);
    }
    return Promise.resolve([]);
  }

  /** Find locations in raw modules from a location in a source file
   * @param {!SourceLocation} sourceLocation
   * @return {!Promise<!Array<!*>>}
   */
  /*async */ sourceLocationToRawLocation(sourceLocation) {
    if (this._impl.sourceLocationToRawLocation) {
      return this._impl.sourceLocationToRawLocation(sourceLocation);
    }
    return Promise.resolve([]);
  }

  /** Find locations in source files from a location in a raw module
   * @param {!RawLocation} rawLocation
   * @return {!Promise<!Array<!*>>}
   */
  /*async */ rawLocationToSourceLocation(rawLocation) {
    if (this._impl.rawLocationToSourceLocation) {
      return this._impl.rawLocationToSourceLocation(rawLocation);
    }
    return Promise.resolve([]);
  }

  /** Return detailed information about a scope
   * @param {string} type
   * @return {!Promise<!ScopeInfo>}
   */
  /*async*/ getScopeInfo(type) {
    if (this._impl.getScopeInfo) {
      return this._impl.getScopeInfo(type);
    }
    return Promise.reject(new Error('getScopeInfo() not implemented'));
  }

  /** List all variables in lexical scope at a given location in a raw module
   * @param {!RawLocation} rawLocation
   * @return {!Promise<!Array<!*>>}
   */
  /*async*/ listVariablesInScope(rawLocation) {
    if (this._impl.listVariablesInScope) {
      return this._impl.listVariablesInScope(rawLocation);
    }
    return Promise.resolve([]);
  }

  /** List all variables in lexical scope at a given location in a raw module
   * @param {!RawLocation} rawLocation
   * @return {!Promise<!{frames: Array<!*>}>}
   */
  /*async*/ getFunctionInfo(rawLocation) {
    if (this._impl.getFunctionInfo) {
      return this._impl.getFunctionInfo(rawLocation);
    }
    return Promise.resolve({frames: []});
  }

  /**
   * @param {string} expression
   * @param {!RawLocation} context
   * @return {!Promise<?{typeInfos: !TypeInfo[], base: !EvalBase}>}
   */
  getTypeInfo(expression, context) {
    if (this._impl.getTypeInfo) {
      return this._impl.getTypeInfo(expression, context);
    }
    return Promise.resolve(null);
  }

  /**
   * @param {string|{base: EvalBase, field: FieldInfo[]}} expressionOrField
   * @param {!RawLocation} context
   * @return {!Promise<?{js:string}>}
   */
  getFormatter(expressionOrField, context) {
    if (this._impl.getFormatter) {
      return this._impl.getFormatter(expressionOrField, context);
    }
    return Promise.resolve(null);
  }

  /**
   * @param {string} rawModuleId
   * @param {string} sourceFileURL
   * @return {!Promise<!Array<number>|undefined>}
   */
  async getMappedLines(rawModuleId, sourceFileURL) {
    if (this._impl.getMappedLines) {
      return this._impl.getMappedLines(rawModuleId, sourceFileURL);
    }
    return Promise.resolve(undefined);
  }
}

/**
 * @param {*} pluginImpl
 * @param {string} name
 * @param {!{language: string, symbol_types: !Array<string>}} supportedScriptTypes
 */
function RegisterExtension(pluginImpl, name, supportedScriptTypes) {
  chrome.devtools.languageServices.registerLanguageExtensionPlugin(
      new ExtensionPluginBase(pluginImpl), name, supportedScriptTypes);
}

</script>
